"use strict";

function demoLogic() {
    console.log("\njsonDemoLogic");

    let monthDic = {
        "January": 31,
        "February": 28,
        "March": 31,
        "April": 30,
        "May": 31,
        "June": 30,
        "July": 31,
        "August": 31,
        "September": 30,
        "October": 31,
        "November": 30,
        "December": 31,
    };

    let monthArr = Object.keys(monthDic);

    // js 8种数据类型 https://www.jb51.net/article/234040.htm
    //      在ES5的时候，我们认知的数据类型确实是 6种：Number、String、Boolean、undefined、object、Null
    //      ES6 中新增了一种 Symbol 。这种类型的对象永不相等，即始创建的时候传入相同的值，可以解决属性名冲突的问题，做为标记。
    //      谷歌67版本中还出现了一种 bigInt。是指安全存储、操作大整数。
    let jsObj = {
        'dic': monthDic,
        'arr': monthArr,
        'str': "stringTest",
        'num': 3.1416,
        'bool': true,
        'nil': null,
        'undef': undefined,
        'nan': NaN,
        'Inf': Infinity,
        'date': new Date(),
    };
    let jsObj2 = {
        'obj': jsObj,
        toJSON() {
            return `{"num":${this.num}, "objtype":${typeof (this.obj)}}`
        },
        'num': 3.1416,
    }


    // 对象 --> json String : JSON.stringify
    // http://www.webkaka.com/tutorial/js/2022/0414116/
    // JSON.stringify 有以下规则。
    //  1, undefined、Function和Symbol不是有效的 JSON 值。
    //      如果在转换过程中遇到任何此类值，则它们要么被忽略（在对象中找到时），要么被更改为null（在数组中找到时）。
    //  2, Boolean, Number和String对象在字符串化过程中被转换为对应的原始值，符合传统的转换语义。 
    //  3, 所有Symbol带键的属性都将被完全忽略，即使在使用replacer函数时也是如此。
    //  4, 数字Infinity和NaN以及null都被认为null。
    //  5, 如果值有toJSON()方法，它负责定义哪些数据将被序列化。
    //  6, 对包含循环引用的对象（对象之间相互引用，形成无限循环）执行此方法，会抛出错误

    console.log('带有 date, undefined, NaN,  Infinity数据的对象 JSON.stringify --> ' + JSON.stringify(jsObj));
    console.log('带有toJSON方法的对象，JSON.stringify --> ' + JSON.stringify(jsObj2));

    // https://zhuanlan.zhihu.com/p/478226524
    // JSON.stringify 的第二参数 replacer(可选)
    //  如果该参数是一个函数，则在序列化过程中，被序列化的值的每个属性都会经过该函数的转换和处理；
    //      作为函数时，它有两个参数，键（key）和值（value），函数类似就是数组方法 map、filter 等方法的回调函数，对每一个属性值都会执行一次该函数
    //      replacer 函数 第一次接受的kv对不是对象的第一个键值对，而是空字符串作为 key 值，value 值是整个对象
    //  如果该参数是一个数组，则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中
    //  如果该参数为 null 或者未提供，则对象所有的属性都会被序列化。

    // JSON.stringify 的第三参数 space(可选): 指定缩进用的空白字符串，用于美化输出
    //  如果参数是个数字，它代表有多少的空格。上限为10。
    //  该值若小于1，则意味着没有空格
    //  如果该参数为字符串（当字符串长度超过10个字母，取其前10个字母），该字符串将被作为空格
    //  如果该参数没有提供（或者为 null），将没有空格

    console.log('设置了space为\\t JSON.stringify --> ' + JSON.stringify(jsObj, null, "\t"));
    console.log('设置了第二个参数replacer返回特定key JSON.stringify --> ' + JSON.stringify(jsObj, ['num', 'nil', 'bool'], 2));
    var replacerCallCount = 0
    console.log('设置了第二个参数replacer 为函数(num对应的值*2, 去除date键值对) JSON.stringify --> ' + JSON.stringify(
        jsObj,
        (key, value) => {
            if (0 == replacerCallCount) {
                console.log("first replacer call, key=" + key); // 第一次接受的kv对不是对象的第一个键值对，而是空字符串作为 key 值，value 值是整个对象
            }
            replacerCallCount += 1;

            if (key == 'num') {
                console.log("apply *2, key=" + key + ', replacerCallCount=' + replacerCallCount);
                return 2 * value;
            } else if (key == 'date') {
                console.log("appley delete, key=" + key + ', replacerCallCount=' + replacerCallCount);
                return undefined; // 返回  undefined表示去除 这个键值对
            }
            return value;
        },
        2));


    // json String --> 对象 ： JSON.parse
    // https://blog.csdn.net/weixin_45890771/article/details/121360643
    console.log('JSON.stringify之前的对象');
    console.dir(jsObj);

    var recieverCallCount = 0;
    let objFromJson = JSON.parse(
        JSON.stringify(jsObj),  // 最简化 JSON.stringify 调用得到的 json 字符串作为输出
        (key,value)=> {
            if (0 == recieverCallCount) {
                console.log("first reciever call, key=" + key); // 查看第一次接受的kv对
            }
            recieverCallCount += 1;

            if (key == 'num') {
                console.log("apply *2, key=" + key + ', recieverCallCount=' + recieverCallCount);
                return 2 * value;
            } else if (key == 'date') {
                console.log("appley delete, key=" + key + ', recieverCallCount=' + recieverCallCount);
                return undefined; // 返回  undefined表示去除 这个键值对
            }
            return value;
    });

    console.log('JSON.stringify 后再调用 JSON.parse 得到的对象');
    console.dir(objFromJson);

}

export { demoLogic };